package com.haixee.parkdemo.auth.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.haixee.parkdemo.auth.client.entity.AuthData;
import com.haixee.parkdemo.auth.dao.*;
import com.haixee.parkdemo.auth.entity.dto.*;
import com.haixee.parkdemo.auth.enums.*;
import com.haixee.parkdemo.auth.jwt.JwsToken;
import com.haixee.parkdemo.auth.jwt.JwtManager;
import com.haixee.parkdemo.auth.model.Acl;
import com.haixee.parkdemo.auth.model.Organize;
import com.haixee.parkdemo.auth.model.Role;
import com.haixee.parkdemo.auth.model.User;
import com.haixee.parkdemo.auth.service.OrganizeService;
import com.haixee.parkdemo.auth.service.UserService;
import com.haixee.parkdemo.auth.utils.PasswordUtil;
import com.haixee.parkdemo.common.context.WebContextHolder;
import com.haixee.parkdemo.common.entity.PageData;
import com.haixee.parkdemo.common.exception.BusinessException;
import com.haixee.parkdemo.common.response.CommonResEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@Slf4j
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UserJobCustomMapper userJobCustomMapper;

    @Autowired
    private UserCustomMapper userCustomMapper;

    @Autowired
    private AclCustomMapper aclCustomMapper;

    @Autowired
    private JwtManager jwtManager;

    @Autowired
    private GroupCustomMapper groupCustomMapper;

    @Autowired
    private OrganizeCustomMapper organizeCustomMapper;

    @Autowired
    private RoleFieldDTOMapper roleFieldDTOMapper;

    @Autowired
    private RoleScopeCustomMapper roleScopeCustomMapper;

    @Autowired
    private RoleCustomMapper roleCustomMapper;

    @Autowired
    private RoleAclCustomMapper roleAclCustomMapper;

    @Autowired
    private OrganizeService organizeService;



    @Override
    @Transactional
    public void addUser(String username, String password, List<Integer> roleIdList) {

        User user = userCustomMapper.selectByUsername(username);

        if (user != null) {
            throw new BusinessException(CommonResEnum.BAD_REQUEST);
        }


        user = new User();
        user.setUsername(username);
        user.setPassword(PasswordUtil.encode(password));

        userMapper.insertSelective(user);

        updateUserRole(user.getId(), roleIdList);
    }

    @Override
    public void updateGroupJob(Integer uid, List<Integer> jobIdList) {

        List<Integer> oldList = userJobCustomMapper.selectByUidAndType(uid, JobType.GROUP.getCode());
        List<Integer> toDeleteList = new ArrayList<>();
        List<Integer> toAddList = new ArrayList<>();

        for (Integer old : oldList) {
            for (Integer newItem : jobIdList) {
                if (old.equals(newItem)) {
                    break;
                }
            }
            toDeleteList.add(old);
        }

        for (Integer newItem : jobIdList) {
            for (Integer old : oldList) {
                if (newItem.equals(old)) {
                    break;
                }
            }
            toAddList.add(newItem);
        }

        if (toDeleteList.size() != 0) {
            userJobCustomMapper.deleteUserJob(uid, toDeleteList);
        }

        if (toAddList.size() != 0) {
            userJobCustomMapper.insertUserJob(uid, toAddList);
        }
    }

    @Override
    public AuthData hasAcl(String token, byte method, String router) {
        Integer uid = null;
        JwsToken jwsToken = null;

        if (StringUtils.isNotBlank(token)) {
            try {
                jwsToken = jwtManager.getOne().getToken(token);

                if (jwsToken != null) {
                    uid = jwsToken.getUid();
                }

            } catch (Exception e) {
                log.warn("[权限判断],权限异常,error:[{}]", e.getMessage());
                e.printStackTrace();
                throw new BusinessException(CommonResEnum.PERMISSION_DENIED);
            }
        }

        User user = userMapper.selectByPrimaryKey(uid);

        if (router.equals("/auth/admin/login")) {
            return getPassAuth(uid);
        }


        Acl acl = aclCustomMapper.selectByMethodAndRouter(method, router);
        if (acl == null) {
            log.info("[权限判断],路由不存在, uid:[{}], method:[{}], router:[{}]", uid, method, router);
            throw new BusinessException(CommonResEnum.PERMISSION_DENIED);
        }

        if (acl.getIsOpen()) {
            return getPassAuth(uid);
        }

        if (user == null) {
            log.info("[权限判断],用户无权限操作, uid:[{}], method:[{}], router:[{}]", uid, method, router);
            throw new BusinessException(CommonResEnum.PERMISSION_DENIED);
        }

        if (router.equals("/auth/admin/checkout")) {
            return getPassAuth(uid);
        }

        Integer roleId = jwsToken.getExtra().getRoleId();
        // 判断角色是否有权限
        if (RoleType.JOB.getType() == jwsToken.getExtra().getRoleType()) {
            if (!roleAclCustomMapper.existRoleAcl(roleId, acl.getId())) {
                throw new BusinessException(CommonResEnum.PERMISSION_DENIED);
            }
        }

        byte roleScope = roleScopeCustomMapper.getScopeByRole(roleId);
        Integer curOrg = jwsToken.getExtra().getOrganizeId();
        List<Integer> underDeptList = new ArrayList<>();
        if (roleScope == RoleScope.SELF.getScope()) {
            underDeptList = organizeService.getUnderTreeById(curOrg);
        } else if (roleScope == RoleScope.DEPT.getScope()) {
            underDeptList = organizeService.getUnderTreeById(curOrg);
            underDeptList.add(curOrg);
        }


        List<String> fieldNameList =  roleFieldDTOMapper.selectFieldNameByRoleIdAndAclId(roleId, acl.getId());
        return new AuthData()
                .setUid(uid)
                .setTenantId(jwsToken.getExtra().getTenantId())
                .setRoleId(roleId)
                .setAclId(acl.getId())
                .setAuth(true)
                .setRoleScope(roleScope)
                .setFieldList(fieldNameList)
                .setUnderDeptList(underDeptList);
    }

    private AuthData getPassAuth(Integer uid) {
        return new AuthData()
                .setUid(uid)
                .setTenantId(-1)
                .setRoleId(-1)
                .setAclId(-1)
                .setAuth(true)
                .setRoleScope((byte)-1)
                .setFieldList(Collections.emptyList())
                .setUnderDeptList(Collections.emptyList());
    }

    @Override
    public List<User> getAll(Integer tenantId) {
        return userCustomMapper.selectAll(tenantId);
    }

    @Override
    public List<UserDTO> getAllWithJob(Integer tenantId) {
        return userCustomMapper.selectAllWithJob(tenantId);
    }

    @Override
    public List<User> getAllUserJob() {
        return userJobCustomMapper.selectAllUserJob();
    }

    @Override
    public User getUser(Integer uid) {
        return userMapper.selectByPrimaryKey(uid);
    }

    @Override
    public PageData<UserAllDTO> getUserDTOList(Integer tenantId, Integer organizeId, Integer page, Integer size) {

        List<Integer> organizeList = null;
        if (organizeId != null) {
            organizeList = organizeService.getUnderTreeById(organizeId);
            organizeList.add(organizeId);
        }

        Page<Object> page1 = PageHelper.startPage(page, size);
        List<UserAllDTO> users = userCustomMapper.selectUserAllDTOList(tenantId, organizeList);


        return new PageData<UserAllDTO>().setPage(page).setTotal(page1.getTotal()).setContent(users);
    }

    @Override
    public List<UserAllDTO> getUserRoleDTO(Integer uid, Integer tenantId, Integer organizeId) {
        return userCustomMapper.selectUserAllDTOListByUid(uid, tenantId, organizeId);
    }

    @Override
    @Transactional
    public void updateUserRole(Integer uid, List<Integer> roleIdList) {

        userCustomMapper.deleteUserRole(uid);
        userCustomMapper.insertUserRole(uid, roleIdList);
    }


}
